#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>
#include "cmd.h"
void exec_cmd(struct cmd *cmd)
{
    if (cmd->input != NULL)
    {
        int fd = open(cmd->input, O_RDONLY);
        if (fd < 0)
        {
            perror("openRD");
            exit(EXIT_FAILURE);
        }
        dup2(fd, 0);
        close(fd);
    }
    if (cmd->output != NULL)
    {
        int fd = open(cmd->output, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
        {
            perror("openWR");
            exit(EXIT_FAILURE);
        }
        dup2(fd, 1);
        close(fd);
    }
    execvp(cmd->argv[0], cmd->argv);
    perror("execvp");
    exit(EXIT_FAILURE);
}

int builtin_cmd(struct cmd *cmd)
{
    char **argv = cmd->argv;
    if (strcmp(argv[0], "cd") == 0)
    {
        chdir(argv[1]);
        return 1;
    }
    if (strcmp(argv[0], "pwd") == 0)
    {
        char cwd[100];
        getcwd(cwd, sizeof(cwd));
        printf("%s\n", cwd);
        return 1;
    }
    if (strcmp(argv[0], "exit") == 0)
    {
        exit(0);
        return 1;
    }
    return 0;
}

void exec_pipe_cmd(int cmdc, struct cmd *cmdv)
{
    if (cmdc == 1)
    {
        exec_cmd(&cmdv[0]);
        return;
    }
    int fds[2];
    if (pipe(fds) != 0)
    {
        perror("pipe");
        exit(EXIT_FAILURE);
    }
    pid_t pid = fork();
    if (pid == 0)
    {
        dup2(fds[1], 1);
        close(fds[0]);
        close(fds[1]);
        exec_pipe_cmd(cmdc - 1, cmdv);
        exit(0);
    }
    wait(NULL);
    dup2(fds[0], 0);
    close(fds[0]);
    close(fds[1]);
    exec_cmd(&cmdv[cmdc - 1]);
}
void read_and_cmp(char *path, char *expected)
{
    int fd = open(path, O_RDONLY);

    char buff[1024];
    int count = read(fd, buff, sizeof(buff));
    buff[count] = 0;

    close(fd);
    assert(strcmp(buff, expected) == 0);
}

void test_exec_cmd()
{
    unlink("test.out");

    pid_t pid = fork();
    if (pid == 0)
    {
        struct cmd cmd = {
            2, {"echo", "hello", NULL}, NULL, "test.out"};
        exec_cmd(&cmd);
    }
    wait(NULL);

    read_and_cmp("test.out", "hello\n");
}

// cat <test.in | sort | uniq | cat >test.out
void test_exec_pipe_cmd()
{
    unlink("test.out");
    struct cmd cmdv[4] = {
        {1, {"cat", NULL}, "test.in", NULL}, {1, {"sort", NULL}, NULL, NULL}, {1, {"uniq", NULL}, NULL, NULL}, {1, {"cat", NULL}, NULL, "test.out"}};
    pid_t pid = fork();
    if (pid == 0)
    {
        // echo "3\n1\n2\n3\n2" | cat >log.txt
        exec_pipe_cmd(4, cmdv);
    }
    wait(NULL);

    read_and_cmp("test.out", "1\n2\n3\n");
}
